\noindent Now there's potential difficulty when there are no variable
arguments. For example, one might expect ``\.{SPRINTF(temp,N,"hello")}''
to expand to ``\.{if(sprintf(temp,"hello",) \dots}''; however, the missing
argument is invalid C~syntax. Since this kind of construction seems to
arise fairly frequently, we have the following special \It{experimental}
rule: \It{if \.{\#.}~is empty and it immediately follows a comma in the
macro expansion, the comma is deleted.} (Whether this is a good idea
remains to be seen. More elaborate alternatives are possible; complain if
you don't like this.)
\dsubsubsection Debugging macros.
^^[macro!debugging]
If one wishes to debug an errant macro, there are several possibilities.
First, one could simply dump its current expansion into the output file.
For example,
{\codemode
@m DUMP(...) [#.]
DUMP(A,B(1),C(x,y,z))
\noindent writes a comma-separated list of the expansions of three macro
calls, surrounded by brackets. Alternatively, one can write information to
the terminal with the built-in function \.{\_DUMPDEF}. The format is the
same as above; just replace \.{DUMP} by \.{\_DUMPDEF}. For each macro call
in its argument list, \.{\_DUMPDEF} writes two lines. The first is a
representation of the original macro definition; the second is its current
expansion.
\dsubsection Outer macros.
^^[macro!expansion!deferring]
\parinserto{2}{5}{0.45}
To defer macro expansion to an external preprocessor, use the `{\ssbf @d}'
command.
As we have said, \WEB\ macros are expanded by \TANGLE\ as it creates the
compilable output file during phase two. This means that the output file,
which is what you will actually be debugging, need not be very readable if
the macros were at all sophisticated (and, therefore, very useful). For
\Fortran\ programming, one has no choice. However, for C~programming it is
desirable to defer macro expansion to the C~preprocessor so that your
output file remains readable. This can, of course, be done with no special
effort just by using the C~preprocessor \.{\#define} command ^^{\>{\PM define}}
as part of your code fragment. Usually, you should insert these in the code
section of the module in which they are first used so that the flow of the
logic is clearest. However, what you usually really want is for your
preprocessor definitions to appear at the top of your file, no matter where
you actually defined them. (There are exceptions to this.) To help you
achieve this effect while maintaining logical clarity, the \WEB\ system
supports the concept of ``\It{outer macros}''. ^^:macro!outer:
These are defined by the command~\atcmd{d}, ^^{\>{@d}}
which is allowed in the definition section only. \WEB\ does not expand
these; rather, it just collects them and copies them at the start of phase
two to the beginning of the output file in a format appropriate for the
relevant language compiler. For symmetry, the command~\atcmd{u} ^^{\>{@u}}
is also provided to undefine an outer macro.
The format of outer macros depends on the language in force. If the current
language is~C, the outer macros should, of course, be in the format
appropriate to the C~preprocessor; an outer C~definition of the form
\atcmd{d A 1} will appear in the beginning of the C~output file as
`\.{\#define A 1}'. Otherwise, the outer macro should be in the format
appropriate to the
\.{m4}~preprocessor. In languages other than~C, the definition
\atcmd{d (B,2)} will appear in the beginning of the output file as
`\.{define(B,2)}'. (With the advent of \FWEB's macro processor, the need
for outer macro definitions in languages other than~C should virtually
disappear.)
For example, when the language is~C, the statements
{\codemode
@d A 1
@d B 2
@d A 2
\noindent will be output as follows:
{\codemode
#define A 1
#define B 2
#undef A
#define A 2
A C~program maintained with
\WEB\ should almost exclusively contain the outer macro,
\atcmd{d}~commands. The
internal, \atcmd{m}~commands should be used only when the \WEB\ system
provides a
macro feature not included in the C~preprocessor. Those features mostly
include stringizing and token pasting (included in the ANSI C~standard, but
not in many extant compilers). If you are using an ANSI C~compiler, your
need for \WEB\ macros will be slight, although a few of the extensions such
as~\.{\#!} or variable arguments may prove useful.
\dsubsection Deferred macros.
Returning now to the internal \WEB\ macros, their order of evaluation
^^[macros!order of evaluation]
requires further discussion. It is important to understand that \It{all}
text, including macro definitions, is collected, tokenized, and stored
during \TANGLE's phase one. ^^{phase!1!\>{TANGLE}}
However, with certain exceptions (involving
the preprocessor) to be described, \It{no macros are actually expanded
during phase one}. The reason for this is that the actual source text in
which the macros are embedded and on which they must operate is not known
until all the text has been collected and placed into the proper modules.
Therefore, it is during phase two, when the completed code text is output,
that macros are expanded. However, in the original design of \WEB\ this led
to an annoying difficulty---namely, \WEB\ macro definitions could be
\It{retroactive}.
^^[macro!retroactive definition of]
The situation arises as follows. In the original design, macros were
allowed only in the definition section of a module. Since all such macros
definitions are collected during phase one, they are all known by the time
code is output during phase two. (Effectively, they are all placed at the
top of the unnamed module.) Thus, a definition made in the definition
section of, say, module~100 could lead to a macro being expanded in module~1
if the code in module~1 contained a reference to that macro name. Although
this is usually the desired effect, it may not be in all cases.
Consider, for example, the following example (see the discussion of
preprocessor commands, below):
{\codemode
@ Here is a peculiar example of retroactive macro definition.
@m A 1
\If(A==1)
\Tab x = A;
\Else
\Tab x = B;
\Endif
@ Another section.
@m A 2
\noindent Here the generated code will be ``\.{x = 2;}'', not ``\.{x = 1}'' or
``\.{x = B;}''. Note also that since the sections, hence the definition
parts, are not required to appear in any particular order,
the order of encountering \WEB\ macro definitions is somewhat indefinite.
This can lead to confusion and hard-to-understand bugs if macros are
redefined and sections are subsequently moved around.
\parinsert{6}{5}{0.5}
Don't define {\ssbf WEB} macros in the code part unless you absolutely
have to.
For complete flexibility, therefore, \FWEB\ introduces the
notion of \It{deferred macros}. ^^:macro!deferred:
Deferred macros are nothing more than \WEB\ macros defined (again
with~\atcmd{m}) in the \It{code} section rather than in the definition section. A deferred macro definition, although it is stored away in a safe place
during phase one, becomes known to the \WEB\ macro processor only at the point
in the code where the definition is made, when the code is being output
during phase two. Thus, the order in which the deferred macro definition
is made is unambiguous (it is determined by the intrinsic structure of the
code, not by the order in which things were explained) and the deferred
definition cannot be inadvertently expanded retroactively. Remembering the
previous discussion of C~preprocessing, we see a complete analogy: deferred
\WEB\ macros are analogous to the use in~C of
\.{\#define}; both are used in the code section. All definitions made in
the definition part behave similarly in that they are placed at the
beginning of the appropriate place: outer macro definitions (\atcmd{d}) are
placed at the beginning of the output file; \WEB\ macro definitions in the
definition part (\atcmd{m}) are effectively placed at the beginning of the
unnamed module.
Most of the time, it will be adequate to define a \WEB\ macro in the
definition part, thereby placing it at the beginning of the unnamed
module, and it is recommended that you do so whenever possible. Reserve
deferred macro definitions for those relatively rare instances when the
order of defining the macro really does matter.
Although deferred \.{@m}~commands work as specified, presently
preprocessor commands (see below) such as~\.{@\#if} or~\.{@\#undef} do not
work as one might expect when referring to deferred macros. Presently, such
commands are executed during phase one (on input), whereas the deferred
macros become known only during phase two (on output). Luckily, there is
an an alternative way of handling preprocessing during output, namely to
use built-in functions such as \.{\_IF}.
^^{\>{\UL IF}}
See the discussion of built-ins below.
\dsubsection Language dependence of macros.
\WEB\ macros are by and large not sensitive to language when they are being
memorized, and with a few exceptions they will expand in the same way no
matter what language is current during output. (An example of an exception
is the behavior of the stringizing operation, which must build a string
using either a single or double quote depending on the language. Another
example is the \.{\_ROUTINE} built-in function ^^{\>{\UL ROUTINE}}
which at presently is defined only for
\Ratfor.) Generally such uniform expansion is desirable. For example,
here is how one can supply a macro definition in~C and a \&{parameter}
statement in
\Fortran\ with a common value:
{\codemode
@ Web macros are known to all languages.
@m NN 100 // One can affect all languages by changing this one number.
@d N NN
\Tab parameter(N=NN) // A fragment of a Fortran code.
@<C functions@>@;
@ A simple C routine.
@<C...@>=
return N;
\noindent If language-sensitive behavior is desired, it can be achieved by
using the \.{\_LANGUAGE} built-in function ^^{\>{\UL LANGUAGE}}
in conjunction with an \.{\_IFELSE}, or the \.{\_LANGUAGE\_NUM} built-in
^^{\>{\UL LANGUAGE\UL NUM}} in conjunction with an \.{\_IFCASE}. See further
discussion below.
\parinsert{2}{5}{0.45}
{\ssbf WEB} macros can be defined from the command line with the option
`{\ssbf -m}'.
\WEB\ macros can also be defined from the command line by using the
command-line option `\.{-m}'. ^^:\>{-m}:
(See the detailed explanation in the section about command-line options.)
Command-line macros are processed at the beginning of the first definition
section. Defining macros from the command line is an efficient way to
customize a code without re-editing it. For example, you can supply fixed
array bounds to a \Fortran\ program employing one of the two equivalent
statements
^^<\>{-m}>
{\codemode
FTANGLE test -mN=1000
FTANGLE test -m"N 1000"
\noindent which is equivalent to saying \atcmd{m N 1000} at the beginning of
the first definition section,
then including statements such as `\.{integer x(0:N)}' in your code.
The facility is
particularly useful in conjunction with the \FWEB\ preprocessor, to be